﻿using OfficeOpenXml;
using OfficeOpenXml.Style;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
using Zero.WebAPI.Framework.Attr;

namespace 请求响应加密.Tools.Excel
{
    public static class ExcelHelper
    {
        private static byte[] ExportToExcel<T>(List<T> data)
        {
            if (data == null || !data.Any())
                throw new ArgumentException("数据为空，无法导出");

            var type = typeof(T);
            var sheetAttr = type.GetCustomAttribute<ExcelSheetAttribute>() ??
                            new ExcelSheetAttribute("Sheet1");

            var properties = type.GetProperties()
                .Where(p => p.GetCustomAttribute<ExcelCellAttribute>() != null)
                .ToList();
            // 处理证书，避免报错提示
            ExcelPackage.LicenseContext = LicenseContext.NonCommercial;

            using var package = new ExcelPackage();
            var sheet = package.Workbook.Worksheets.Add(sheetAttr.SheetName);

            int startRow = sheetAttr.StartRow == 0 ? 1 : sheetAttr.StartRow;
            int colIndex = 1;
            int rowCount = data.Count();

            // 写入标题
            if (sheetAttr.ShowColumnHeader)
            {
                rowCount+= startRow;
                foreach (var prop in properties)
                {
                    ExcelCellAttribute? excelAttr = prop.GetCustomAttribute<ExcelCellAttribute>();
                    var header = excelAttr?.CellName ?? prop.Name;
                    sheet.Cells[startRow, colIndex].Value = header;
                    sheet.Cells[startRow, colIndex].Style.Font.Bold = true;
                    sheet.Cells[startRow, colIndex].Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;

                    string startAddrStr = GetCharCode(colIndex - 1) + (startRow + 1).ToString();
                    string endAddrStr = GetCharCode(colIndex - 1) + rowCount.ToString();

                    // sheet.Cells["A2:A31"].Style = .... 统一地设置属性，高效
                    #region 统一设置单元格样式
                    var cellRange = sheet.Cells[$"{startAddrStr}:{endAddrStr}"];

                    // 如果属性有自定义样式，则应用
                    if (excelAttr != null)
                    {
                        // 1. 设置字体样式
                        cellRange.Style.Font.Name = excelAttr.FontName;
                        cellRange.Style.Font.Size = excelAttr.FontSize;
                        cellRange.Style.Font.Bold = excelAttr.FontBold;
                        cellRange.Style.Font.Italic = excelAttr.FontItalic;
                        cellRange.Style.Font.UnderLine = excelAttr.UnderLine;

                        // 设置字体颜色（从字符串解析为Color）
                        if (!string.IsNullOrEmpty(excelAttr.FontColor))
                        {
                            var fontColor = Color.FromName(excelAttr.FontColor);
                            if (fontColor.IsKnownColor)
                                cellRange.Style.Font.Color.SetColor(fontColor);
                        }

                        // 2. 设置单元格样式
                        cellRange.Style.Indent = excelAttr.Indent;
                        cellRange.Style.WrapText = excelAttr.WrapText;
                        cellRange.Style.TextRotation = excelAttr.TextRotation;

                        // 3. 设置边框
                        if (!string.IsNullOrEmpty(excelAttr.BorderStyle))
                        {
                            var borderStyle = (ExcelBorderStyle)Enum.Parse(typeof(ExcelBorderStyle), excelAttr.BorderStyle);
                            var borders = cellRange.Style.Border;

                            // 解析边框设置（格式："1,1,1,1" 表示 上,左,下,右）
                            var borderParts = excelAttr.Border.Split(',');
                            if (borderParts.Length == 4)
                            {
                                if (borderParts[0] == "1") borders.Top.Style = borderStyle;
                                if (borderParts[1] == "1") borders.Left.Style = borderStyle;
                                if (borderParts[2] == "1") borders.Bottom.Style = borderStyle;
                                if (borderParts[3] == "1") borders.Right.Style = borderStyle;
                            }
                        }

                        // 4. 设置背景色
                        if (!string.IsNullOrEmpty(excelAttr.BackgroundColor))
                        {
                            var bgColor = Color.FromName(excelAttr.BackgroundColor);
                            if (bgColor.IsKnownColor)
                            {
                                cellRange.Style.Fill.PatternType = (ExcelFillStyle)Enum.Parse(
                                    typeof(ExcelFillStyle),
                                    excelAttr.BackgroundStyle
                                );
                                cellRange.Style.Fill.BackgroundColor.SetColor(bgColor);
                            }
                        }
                    }
                    #endregion

                    colIndex++;
                }
                startRow++; // 数据从下一行开始
            }

            // 写入数据
            for (int i = 0; i < data.Count; i++)
            {
                var item = data[i];
                for (int j = 0; j < properties.Count; j++)
                {
                    var value = properties[j].GetValue(item);
                    sheet.Cells[startRow + i, j + 1].Value = value;
                }
            }

            sheet.Cells[sheet.Dimension.Address].AutoFitColumns();

            return package.GetAsByteArray();
        }

        // 可选：保存为文件
        public static void SaveToFile<T>(List<T> data, string filePath)
        {
            FileInfo fileInfo = new FileInfo(filePath);
            string extension = fileInfo.Extension;
            string[] extNames = new string[] { ".xlsx", "xls" };
            if (!extNames.Contains(extension))
                throw new Exception("文件扩展名错误，请检查扩展名");
            var bytes = ExportToExcel(data);
            File.WriteAllBytes(filePath, bytes);
        }

        private static char GetCharCode(int idx)
        {
            return (char)('A' + idx);
        }
    }

}
